%%%---------------------------------------------------------------------------------------
%%% @author     Stuart Jackson <simpleenigma@gmail.com> [http://erlsoft.org]
%%% @copyright  2006 - 2007 Simple Enigma, Inc. All Rights Reserved.
%%% @doc        ERML evaluation routines
%%% @reference  See <a href="http://erlsoft.org/modules/erlweb" target="_top">Erlang Software Framework</a> for more information
%%% @reference See <a href="http://erlweb.googlecode.com" target="_top">ErlWeb Google Code Repository</a> for more information
%%% @version    0.0.2
%%% @since      0.0.1
%%% @end
%%%
%%%
%%% The MIT License
%%%
%%% Copyright (c) 2007 Stuart Jackson, Simple Enigma, Inc. All Righs Reserved
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%%% THE SOFTWARE.
%%%
%%%
%%%---------------------------------------------------------------------------------------

-module(erml_eval).
-author('sjackson@simpleenigma.com').
-include("../include/erml.hrl").


-compile(export_all).



eval(String,ERML) when is_list(String) ->
	case erl_scan:string(String ++ ".") of
		{ok,Tokens,_EndLine} ->
%			io:format("~p~n",[Tokens]),
			NewTokens = var_sub(Tokens,build_var(ERML)),
%			io:format("~p~n",[NewTokens]),
			case erl_parse:parse_exprs(NewTokens) of
				{ok,AbsForm} -> 
%					io:format("~p~n",[AbsForm]),
					E = (catch erl_eval:exprs(AbsForm,[])),
%					io:format("~p~n",[E]),
					case E of
						{value,true,_NewBindings} -> true;   % Evaluation was complete and was true
						{value,false,_NewBindings} -> false; % Evaluation was complete but was false
						{value,Value,_NewBindings} -> Value; % Evaluation was complete and value is returned
						_EvalErrorInfo ->                    % Trap erros from evaluation and returns false
							io:format("ERL_EVAL Error: ~p~n",[_EvalErrorInfo]),
							false
					end;
				{error,_ParseErrorInfo} -> 
%					io:format("ERL_PARSE Error: ~p~n",[_ParseErrorInfo]),
					false
			end;
		{error,_ScanErrorInfo,_Line} -> 
%			io:format("ERL_SCAN Error: ~p~n",[_ScanErrorInfo]),
			false
	end.
		

build_var(ERML) -> 
	Basic = [{absolute_uri,ERML#erml.absolute_uri},
			 {http_version,ERML#erml.http_version},
			 {method,ERML#erml.method},
			 {request_line,ERML#erml.request_line},			 
			 {request_uri,ERML#erml.request_uri},
			 {remote_addr,ERML#erml.remove_addr}],
	Headers = clean_headers(ERML#erml.parsed_header),
	lists:umerge([Basic,
				  Headers,
				  lists:usort(ERML#erml.var)]).


clean_headers(Headers) ->
	NewHeaders = lists:map(fun(H) -> 
			{Key,Value} = H,
			
			{_,NewKey,_} = regexp:gsub(Key,"-","_"),
			{list_to_atom(NewKey),Value}
		end,Headers),
	lists:usort(NewHeaders).




var_sub(Tokens,Var) -> 
	NewTokens = lists:foldl(fun(O,T) -> op_replace(T,O) end,Tokens,?OPERANDS),
	lists:foldl(fun(V,T2) -> token_replace(T2,V) end,NewTokens,Var).


op_replace(TokenList,{Key,Value}) -> op_replace(TokenList,Key,Value).
op_replace(TokenList,Key,Value) -> 
	lists:map(fun(T) ->
		case T of
			{_,_,Key} -> {Value,1};
			_ -> T
		end	
	end,TokenList).


	


token_replace(TokenList,{Key,Value}) -> token_replace(TokenList,Key,Value).
token_replace(TokenList,Key,Value) -> 
	lists:map(fun(T) -> 
		case T of
			{_,_,Key} -> type(Value);
			_ -> T
		end
	
		end,TokenList).



type(Value) when is_integer(Value) -> {integer,1,Value};
type(Value) when is_float(Value)   -> {float,1,Value};
type(Value) when is_list(Value)    -> {list,1,Value};
type(Value) when is_atom(Value)    -> {atom,1,Value}.